#include <Hal/Manager.h>
#include <Utils/Math.h>
#include <BootConsole.h>

extern "C" uintptr_t _end;

namespace Hal
{
	Multiboot2::Header *Manager::Mb2Hdr;
	
	bool Manager::ValidateParameters(uint64_t Mb2Ptr, uint64_t Mb2Signature)
	{
		if (Mb2Signature != 0x36D76289)
			return false;
		
		if (Mb2Ptr == 0)
			return false;
		
		Mb2Hdr = (Multiboot2::Header *) UPPERMEM(Mb2Ptr);
		
		if (!Mb2Hdr->HasTag(Multiboot2::Header::MemInfo) || !Mb2Hdr->HasTag(Multiboot2::Header::MemoryMap))
			return false;
		
		return true;
	}
	
	void Manager::Halt()
	{
		asm volatile ("CLI\nHLT");
	}
	
	uint64_t Manager::GetMemoryKbs()
	{
		Multiboot2::TagHeader &hdr = Mb2Hdr->GetTag(Multiboot2::Header::MemInfo);
		uint32_t *memInfoTag = (uint32_t *) &hdr;

		return Utils::Math::CeilInt(memInfoTag[3], 1024) + 1024;
	}
	
	const Multiboot2::Header &Manager::GetMb2Header()
	{
		return *Mb2Hdr;
	}
	
	uintptr_t Manager::GetFirstAvailablePage()
	{
		uintptr_t limit = _end;
		uintptr_t endOfMb = (uintptr_t) Mb2Hdr + Mb2Hdr->GetSize();
		if (endOfMb > limit)
			limit = endOfMb;
		
		return Utils::Math::CeilInt(limit, 0x1000);
	}
}
